from rest_framework.routers import SimpleRouter, path, Route, DynamicRoute

from django.conf import settings


class Router(SimpleRouter):
    """viewssets url后缀 增加 post delete put。实现post请求增删改"""
    routes = [
        # List route.
        Route(
            url=r'^{prefix}{method}{trailing_slash}$',
            mapping={'get': 'list'},
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        # 新增
        Route(
            url=r'^{prefix}{method}{trailing_slash}$',
            mapping={'post': 'create'},
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        # Dynamically generated list routes. Generated using
        # @action(detail=False) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{url_path}{method}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=False,
            initkwargs={}
        ),
        # Detail route.
        Route(
            url=r'^{prefix}/{lookup}{method}{trailing_slash}$',
            mapping={'get': 'retrieve'},
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
        # 修改
        Route(
            url=r'^{prefix}/{lookup}{method}{trailing_slash}$',
            mapping={'post': 'update'},
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
        Route(
            url=r'^{prefix}/{lookup}{method}{trailing_slash}$',
            mapping={'post': 'destroy'},
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
        # Dynamically generated detail routes. Generated using
        # @action(detail=True) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}{method}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=True,
            initkwargs={}
        ),
    ]

    # 生成 url 路由 路由映射到 mixins 方法上
    method_map = {
        v: f'/{k}'
        for k, v in settings.METHODS_MAP.items()
    }

    def get_urls(self):
        """
        重写 生成url方法
        具体在url增加 post put delete逻辑
        :return:
        example
            url -> /user/post/ -> create
            url -> /user/put/ ->  update
            url -> /user/delete/ ->  destroy
        """
        ret = []

        for prefix, viewset, basename in self.registry:
            lookup = self.get_lookup_regex(viewset)
            routes = self.get_routes(viewset)

            for route in routes:

                # Only actions which actually exist on the viewset will be bound
                mapping = self.get_method_map(viewset, route.mapping)
                if not mapping:
                    continue
                # build 增加后缀
                method = mapping.get('post')
                regex = route.url.format(
                    prefix=prefix,
                    lookup=lookup,
                    trailing_slash=self.trailing_slash,
                    method=self.method_map.get(method, '')
                )

                # If there is no prefix, the first part of the url is probably
                #   controlled by project's urls.py and the router is in an app,
                #   so a slash in the beginning will (A) cause Django to give
                #   warnings and (B) generate URLS that will require using '//'.
                if not prefix:
                    if self._url_conf is path:
                        if regex[0] == '/':
                            regex = regex[1:]
                    elif regex[:2] == '^/':
                        regex = '^' + regex[2:]

                initkwargs = route.initkwargs.copy()
                initkwargs.update({
                    'basename': basename,
                    'detail': route.detail,
                })

                view = viewset.as_view(mapping, **initkwargs)
                name = route.name.format(basename=basename)
                ret.append(self._url_conf(regex, view, name=name))

        return ret
